// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-12-16

package counter

import (
	"sync"
	"sync/atomic"
	"time"
)

type (
	ProcessCounter interface {
		Add(uid, name string, time time.Time)
		Del(uid string)
		Get(uid string) (tm time.Time, has bool)
		GetCreatedCount() int64
		GetFatalCount() int64
		GetMapper() (mapper map[string]string)
		GetMapperTime() (mapper map[string]time.Time)
		GetRunningCount() int64
		GetStartedCount() int64
		GetStoppedCount() int64
		IncrCreatedCount()
		IncrFatalCount()
	}

	process struct {
		mapperName map[string]string
		mapperTime map[string]time.Time
		mu         *sync.RWMutex

		CreatedCount int64
		FatalCount   int64
		RunningCount int64
		StartedCount int64
		StoppedCount int64
	}
)

func (o *process) Add(uid, name string, time time.Time) {
	o.mu.Lock()
	defer o.mu.Unlock()

	if _, ok := o.mapperTime[uid]; !ok {
		o.mapperName[uid] = name
		o.mapperTime[uid] = time
		atomic.AddInt64(&o.RunningCount, 1)
		atomic.AddInt64(&o.StartedCount, 1)
	}
}

func (o *process) Del(uid string) {
	o.mu.Lock()
	defer o.mu.Unlock()

	if _, ok := o.mapperTime[uid]; ok {
		delete(o.mapperName, uid)
		delete(o.mapperTime, uid)
		atomic.AddInt64(&o.RunningCount, -1)
		atomic.AddInt64(&o.StoppedCount, 1)
	}
}

func (o *process) Get(uid string) (tm time.Time, has bool) {
	o.mu.RLock()
	tm, has = o.mapperTime[uid]
	o.mu.RUnlock()
	return
}

func (o *process) GetMapper() (mapper map[string]string) {
	o.mu.RLock()
	mapper = o.mapperName
	o.mu.RUnlock()
	return
}

func (o *process) GetMapperTime() (mapper map[string]time.Time) {
	o.mu.RLock()
	mapper = o.mapperTime
	o.mu.RUnlock()
	return
}

func (o *process) GetCreatedCount() int64 { return atomic.LoadInt64(&o.CreatedCount) }
func (o *process) GetFatalCount() int64   { return atomic.LoadInt64(&o.FatalCount) }
func (o *process) GetRunningCount() int64 { return atomic.LoadInt64(&o.RunningCount) }
func (o *process) GetStartedCount() int64 { return atomic.LoadInt64(&o.StartedCount) }
func (o *process) GetStoppedCount() int64 { return atomic.LoadInt64(&o.StoppedCount) }

func (o *process) IncrCreatedCount() { atomic.AddInt64(&o.CreatedCount, 1) }
func (o *process) IncrFatalCount()   { atomic.AddInt64(&o.FatalCount, 1) }

func (o *process) init() *process {
	o.mapperName = make(map[string]string)
	o.mapperTime = make(map[string]time.Time)
	o.mu = &sync.RWMutex{}
	return o
}
